package com.ray.com.ray.demo.utils;

import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.aspectj.lang.JoinPoint;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;

/**
 * Created by ray on 2017/5/22.
 */
public class ReflexUtil {

    //TODO 判断是否基本类型
//    private static String[] types = { "java.lang.Integer", "java.lang.Double",
//            "java.lang.Float", "java.lang.Long", "java.lang.Short",
//            "java.lang.Byte", "java.lang.Boolean", "java.lang.Char",
//            "java.lang.String", "int", "double", "long", "short", "byte",
//            "boolean", "char", "float", "java.math.BigDecimal" };
//
//    private static List<String> typeList;
//
//    static {
//        typeList = Arrays.asList(types);
//    }

    public static String getParamStr(String[] paramNames, JoinPoint joinPoint, boolean printCollection){
        Object[] args = joinPoint.getArgs();
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        for(int k=0; k<args.length; k++){
            Object arg = args[k];
            // 获取对象类型
            //String typeName = arg.getClass().getName();
            //if (typeList.contains(typeName)) {
            if( isWrapClass(arg.getClass()) ){
                sb.append(paramNames[k]+"=" + arg+"; ");
            }else{//自定义类型 or 非基本类型
                sb.append(getFieldsValue(arg, printCollection));
            }
        }
        sb.append("}");
        return sb.toString();
    }

    /**
     * 得到参数的值
     * @param obj
     */
    public static String getFieldsValue(Object obj,boolean printCollection) {
        StringBuilder sb = new StringBuilder();
        Field[] fields = obj.getClass().getDeclaredFields();
        sb.append("[");
        for (Field f : fields) {
            f.setAccessible(true);
            try {
                //if (typeList.contains(f.getType().getName())){
                if( isWrapClass(f.getType()) ){
                    sb.append(f.getName() + "=" + f.get(obj)+";");
                }else{
                    Object objVal = f.get(obj);
                    //TODO 待完善Map, Set, Collection
                    if(objVal instanceof List && printCollection){//是集合类型
                        sb.append(f.getName() + "={");
                        List list = (List)objVal;
                        for (Object o: list) {
                            sb.append(ReflectionToStringBuilder.toString(o, ToStringStyle.DEFAULT_STYLE)+";");
                        }
                        sb.append("}");
                    }else{
                        sb.append(f.getName() + "=" + ReflectionToStringBuilder.toString(objVal, ToStringStyle.DEFAULT_STYLE));
                    }
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        sb.append("]");
        return sb.toString();
    }

    public static String[] getFieldsName(Class cls, String clazzName, String methodName) throws NotFoundException {
        ClassPool pool = ClassPool.getDefault();
        //ClassClassPath classPath = new ClassClassPath(this.getClass());
        ClassClassPath classPath = new ClassClassPath(cls);
        pool.insertClassPath(classPath);

        CtClass cc = pool.get(clazzName);
        CtMethod cm = cc.getDeclaredMethod(methodName);
        MethodInfo methodInfo = cm.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if (attr == null) {
            // BizException
        }
        String[] paramNames = new String[cm.getParameterTypes().length];
        int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
        for (int i = 0; i < paramNames.length; i++){
            paramNames[i] = attr.variableName(i + pos); //paramNames即参数名
        }
        return paramNames;
    }

    public static boolean isWrapClass(Class clz) {
        try {
            return ((Class) clz.getField("TYPE").get(null)).isPrimitive();
        } catch (Exception e) {
            return clz.getName().equals("java.lang.String") || clz.isPrimitive();
        }
    }

}
